/******************************************************************************
MIT License

Copyright (c) 2025 RV4kids

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

===============================================================================

🌟 里程碑时刻：2025-11-15
🤖 本模块由 DeepSeek AI 辅助创作完成

🙏 特别致谢：
   - 感谢 BH6BAO 的原始开源贡献
   - 感谢 ecos 团队的老师们悉心指导
   - 感谢所有开源硬件社区的贡献者

🛠️ 测试平台：studio.oscc.cc
🎯 项目名称：YaXin RISC-V 处理器核心

💝 模块命名：YaXin_RISC-V 核心运算单元扩展版 - "全能心算单元"
   在 YaXin 核心中，本模块承担着核心的算术运算功能，
   如同心脏中的"心室"，负责数据的压缩和泵送，为整个系统提供计算动力。

🔧 模块功能：
   - 32位有符号加减乘除四则运算
   - 64位乘法结果输出
   - 32位除法结果（商+余数）输出
   - 精简8位数据总线接口
   - 自动化的配置和结果读取流程

📝 设计理念：
   - "心房单元" - 指令预取和分支预测
   - "动脉单元" - 数据通路和流水线控制  
   - "静脉单元" - 回写和结果转发
   - "神经单元" - 中断和异常处理

===============================================================================

🎯 模块功能详解 - 加减乘除全能运算器
🤖 基于已验证的乘除模块扩展加减法功能
🛠️ 支持渐进式测试和验证

需要和以下文件一同上传综合：

- ../core/long_slow_div_denom_reg.v
- ../core/mul_div_32.v
- ../core/absolute_value.v

综合的版图效果：

- mul_div_add_sub_compact.png

===============================================================================

🌟 创作历程 - 体现 DeepSeek 能力

【设计思路】：
"在现有乘除模块基础上，通过精简IO接口扩展加减法功能，
采用稳扎稳打的渐进式开发策略，确保每个阶段都综合通过"

【实现策略】：
1. 阶段1：基础IO通路 + 乘除模块实例化（输入连接）
2. 阶段2：异步等待机制 + 结果传递（等待逻辑）  
3. 阶段3：完整64位支持 + 动态输出（终极版本）

【技术特点】：
- 复用已验证的乘除模块，确保核心运算正确性
- 精简8位总线接口，减少IO引脚占用
- 动态输出长度：乘除法8字节，加减法4字节
- 完整的异步状态管理机制

******************************************************************************/

`timescale 1ns/1ps

/**
 * @brief 加减乘除全能运算模块 - 支持32位有符号四则运算
 * 
 * @details
 * 本模块通过8位精简数据总线接口，支持32位有符号数的加减乘除运算。
 * 采用分步配置和读取的机制，通过状态机管理整个运算流程。
 * 
 * 🎯 核心特性：
 * - 乘法：64位完整结果输出
 * - 除法：64位结果（高32位商，低32位余数）
 * - 加法：32位结果零扩展到64位
 * - 减法：32位结果零扩展到64位
 * - 动态输出：乘除法8字节，加减法4字节
 * 
 * 🔄 工作流程：
 * 1. 配置模式(mode=0)：分8步输入操作数A、B和控制字
 * 2. 自动计算：根据操作码执行相应运算
 * 3. 读取模式(mode=1)：分步读取运算结果
 * 
 * 📊 操作码定义：
 * - 2'b00: 乘法 (64位输出)
 * - 2'b01: 除法 (64位输出)  
 * - 2'b10: 加法 (32位输出)
 * - 2'b11: 减法 (32位输出)
 */
module mul_div_add_sub_compact(
    // ========== 精简IO接口 ==========
    input  wire       clk,          // 🔄 系统时钟 - 驱动所有同步逻辑
    input  wire       rst_n,        // 🔄 异步复位 - 低电平有效，清零所有状态
    input  wire       start,        // 🚀 启动脉冲 - 每个配置/读取步骤的触发信号
    input  wire       mode,         // 🎛️  模式选择 - 0=写配置, 1=读结果
    input  wire [7:0] data_in,      // 📥 8位数据输入 - 用于配置操作数和控制字
    output wire [7:0] data_out,     // 📤 8位数据输出 - 用于读取运算结果
    output wire       ready         // ✅ 系统就绪 - 高电平表示可接受新操作
);

    // ========== 内部寄存器定义 ==========
    // 📊 运算数据存储
    reg [31:0] operand_a;      // ➕ 操作数A - 32位有符号数
    reg [31:0] operand_b;      // ➕ 操作数B - 32位有符号数  
    reg [1:0]  opcode;         // 🎯 操作码 - 决定执行哪种运算
    reg [63:0] result;         // 📈 64位结果 - 支持乘法64位和除法双32位输出
    reg        result_valid;   // ✅ 结果有效标志 - 表示计算结果已就绪
    
    // 🔄 状态控制寄存器
    reg [2:0] config_step;     // ⚙️  配置步骤计数器 - 0-7对应8个配置字节
    reg [2:0] output_step;     // 📤 输出步骤计数器 - 0-7支持8字节输出
    reg       waiting_mul_div; // ⏳ 乘除等待标志 - 高电平表示等待乘除模块完成
    
    // ========== 乘除模块实例化 ==========
    // 🔗 连接现有乘除模块，复用已验证的乘除运算核心
    wire        mul_div_enable_out; // ✅ 乘除模块完成信号
    wire [63:0] mul_div_z;          // 📊 乘除模块64位结果
    wire        mul_div_ov;         // ⚠️  乘除模块溢出标志
    reg         mul_div_enable_in;  // 🚀 乘除模块使能信号
    
    /**
     * @brief 乘除模块实例化 - 复用BH6BAO的已验证设计
     * 
     * @note 该模块提供：
     * - 32位有符号乘法（64位结果）
     * - 32位有符号除法（32位商 + 32位余数）
     * - 溢出检测和除零处理
     */
    mul_div_32 u_mul_div(
        .clk(clk),                          // 🔄 时钟同步
        .reset_n(rst_n),                    // 🔄 异步复位
        .enable_in(mul_div_enable_in),      // 🚀 计算使能 - 我们控制何时启动
        .x(operand_a),                      // ➕ 操作数A - 直接连接我们的寄存器
        .y(operand_b),                      // ➕ 操作数B - 直接连接我们的寄存器
        .mul0_div1(opcode[0]),              // 🎯 运算类型 - 0=乘法, 1=除法
        .x_signed0_unsigned1(1'b0),         // 🔢 有符号运算 - 固定为有符号
        .y_signed0_unsigned1(1'b0),         // 🔢 有符号运算 - 固定为有符号
        .enable_out(mul_div_enable_out),    // ✅ 完成指示 - 告诉我们计算何时完成
        .z(mul_div_z),                      // 📊 计算结果 - 64位完整结果
        .ov(mul_div_ov)                     // ⚠️  溢出标志 - 错误检测
    );
    
    // ========== 配置和计算逻辑 ==========
    /**
     * @brief 配置状态机和计算控制
     * 
     * @details
     * 在配置模式(mode=0)下，通过8个步骤接收操作数A、B和控制字。
     * 根据操作码决定执行方式：
     * - 乘除法：启动乘除模块并等待其完成
     * - 加减法：立即计算并标记结果有效
     * 
     * 🔄 配置步骤序列：
     * 步骤0-3: operand_a[7:0] → [15:8] → [23:16] → [31:24]
     * 步骤4-7: operand_b[7:0] → [15:8] → [23:16] → [31:24] + 控制字
     */
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // 🔄 复位初始化 - 清零所有状态
            config_step <= 3'd0;
            operand_a <= 32'd0;
            operand_b <= 32'd0;
            opcode <= 2'b00;
            result_valid <= 1'b0;
            result <= 64'd0;
            mul_div_enable_in <= 1'b0;
            waiting_mul_div <= 1'b0;
        end else begin
            mul_div_enable_in <= 1'b0; // 🔄 默认关闭乘除模块使能
            
            if (waiting_mul_div) begin
                // ⏳ 等待乘除模块完成状态
                if (mul_div_enable_out) begin
                    // ✅ 乘除计算完成
                    waiting_mul_div <= 1'b0;
                    result <= mul_div_z; // 📊 使用乘除模块的完整64位结果
                    result_valid <= 1'b1; // 🎯 标记结果有效
                end
            end else if (!mode && start) begin 
                // ⚙️ 配置模式 - 接收操作数和控制字
                case (config_step)
                    3'd0: operand_a[7:0]   <= data_in;   // 📥 A字节0
                    3'd1: operand_a[15:8]  <= data_in;   // 📥 A字节1  
                    3'd2: operand_a[23:16] <= data_in;   // 📥 A字节2
                    3'd3: operand_a[31:24] <= data_in;   // 📥 A字节3
                    3'd4: operand_b[7:0]   <= data_in;   // 📥 B字节0
                    3'd5: operand_b[15:8]  <= data_in;   // 📥 B字节1
                    3'd6: operand_b[23:16] <= data_in;   // 📥 B字节2
                    3'd7: begin
                        operand_b[31:24] <= data_in;     // 📥 B字节3
                        opcode <= data_in[1:0];          // 🎯 设置操作码
                        
                        // 🧮 根据操作码执行相应运算
                        case (data_in[1:0])
                            2'b00, 2'b01: begin 
                                // ✖️➗ 乘除法 - 启动乘除模块并等待
                                mul_div_enable_in <= 1'b1;  // 🚀 启动乘除模块
                                waiting_mul_div <= 1'b1;    // ⏳ 进入等待状态
                                result_valid <= 1'b0;       // ❌ 结果暂时无效
                            end
                            2'b10: begin 
                                // ➕ 加法 - 立即计算
                                result <= {32'd0, operand_a + operand_b}; 
                                result_valid <= 1'b1;       // ✅ 结果立即有效
                            end
                            2'b11: begin 
                                // ➖ 减法 - 立即计算  
                                result <= {32'd0, operand_a - operand_b};
                                result_valid <= 1'b1;       // ✅ 结果立即有效
                            end
                        endcase
                    end
                endcase
                
                // 🔄 更新配置步骤计数器
                if (config_step < 3'd7)
                    config_step <= config_step + 1;
                else
                    config_step <= 3'd0;
            end
        end
    end
    
    // ========== 输出逻辑 ==========
    /**
     * @brief 动态输出长度控制
     * 
     * @details
     * 根据操作码决定输出字节数：
     * - 乘除法(opcode[1]==0): 8字节输出（64位）
     * - 加减法(opcode[1]==1): 4字节输出（32位）
     * 
     * 📊 输出格式（小端序）：
     * 字节0: result[7:0]
     * 字节1: result[15:8] 
     * 字节2: result[23:16]
     * 字节3: result[31:24]
     * 字节4: result[39:32] （仅乘除法）
     * 字节5: result[47:40] （仅乘除法）
     * 字节6: result[55:48] （仅乘除法） 
     * 字节7: result[63:56] （仅乘除法）
     */
    
    // 🎯 根据操作码确定最大输出步数
    wire [2:0] max_output_step = (opcode[1] == 1'b0) ? 3'd7 : 3'd3;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            output_step <= 3'd0;
        end else if (mode && start && result_valid) begin
            // 📤 读取模式 - 每次start脉冲推进输出步骤
            if (output_step < max_output_step)
                output_step <= output_step + 1;
            else
                output_step <= 3'd0; // 🔄 循环回到开始
        end else if (!result_valid) begin
            // ❌ 结果无效时复位输出状态
            output_step <= 3'd0;
        end
    end
    
    // ========== 输出数据选择 ==========
    /**
     * @brief 输出字节选择器
     * 
     * @details
     * 根据output_step选择相应的结果字节输出。
     * 支持8字节输出，但加减法时只使用前4字节。
     */
    reg [7:0] output_data;
    
    always @(*) begin
        case (output_step)
            3'd0: output_data = result[7:0];    // 📤 字节0 - 最低有效字节
            3'd1: output_data = result[15:8];   // 📤 字节1
            3'd2: output_data = result[23:16];  // 📤 字节2  
            3'd3: output_data = result[31:24];  // 📤 字节3
            3'd4: output_data = result[39:32];  // 📤 字节4（仅乘除法）
            3'd5: output_data = result[47:40];  // 📤 字节5（仅乘除法）
            3'd6: output_data = result[55:48];  // 📤 字节6（仅乘除法）
            3'd7: output_data = result[63:56];  // 📤 字节7（仅乘除法）- 最高有效字节
            default: output_data = 8'd0;        // 🛑 默认输出零
        endcase
    end
    
    // ========== 状态指示逻辑 ==========
    /**
     * @brief 系统就绪信号生成
     * 
     * @details
     * ready信号在以下条件同时满足时为高：
     * 1. 不在配置过程中 (config_step == 0)
     * 2. 不在输出过程中 (output_step == 0)  
     * 3. 不在等待乘除结果 (waiting_mul_div == 0)
     * 
     * 这确保系统只在空闲状态接受新操作。
     */
    assign ready = (config_step == 3'd0) && (output_step == 3'd0) && !waiting_mul_div;
    assign data_out = output_data; // 📤 直接输出选择的数据字节

endmodule